/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.gui.activity;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import de.fuberlin.kosmik.R;
import de.fuberlin.kosmik.StrUtils;
import de.fuberlin.kosmik.data.osmt.OsmtBundle;
import de.fuberlin.kosmik.data.osmt.OsmtData;
import de.fuberlin.kosmik.data.osmt.OsmtDataFactory;
import de.fuberlin.kosmik.data.osmt.OsmtFeature;
import de.fuberlin.kosmik.data.osmt.OsmtFeatureRecord;
import de.fuberlin.kosmik.data.osmt.OsmtObjectException;
import de.fuberlin.kosmik.gui.dialog.Dialogs;
import de.fuberlin.kosmik.gui.view.adapter.TagBundleListAdapter;
import de.fuberlin.kosmik.gui.view.adapter.TagBundleListAdapter.ListItem;
import de.fuberlin.kosmik.log.Constants;

/**
 * TagBundleActivity shows a bunch of tags. From TagBundleActivity out there is
 * the possibility to edit individual tags, delete or add. The TagBundleActivity
 * is called by TagPickerActivity and calls the TagEditingActivity.
 * 
 * @author Johannes
 */
public class TagBundleActivity extends Activity {

	/**
	 * Download the photo image of the first feature asynchron.
	 */
	class DownloadImageTask extends AsyncTask<OsmtFeatureRecord, Void, Drawable> {

		@Override
		protected Drawable doInBackground(OsmtFeatureRecord... params) {
			if (params.length > 0) {
				Drawable drawable;
				if ((drawable = OsmtFeatureRecord.downloadFeaturePhoto(params[0])) != null
						|| (drawable = OsmtFeatureRecord.downloadFeatureRenderImage(params[0])) != null) {
					return drawable;
				}
			}
			return null;
		}

		@Override
		protected void onPostExecute(Drawable result) {
			if (result != null)
				imgBundleImageView.setImageDrawable(result);
			super.onPostExecute(result);
		}

	}

	private ListView lstBundleView;
	private ImageView imgBundleImageView;
	private int osmtBundleId;
	private OsmtBundle osmtBundle;
	private static final int INTENT_TAG_EDIT = 1;
	private static final int INTENT_TAG_ADD = 2;
	private DownloadImageTask downloadImageTask;
	private OsmtData osmtData;
	private Intent resultIntent = new Intent();

	/**
	 * Bridge from click event (getOnKeyValueItemClickListener) to processed
	 * result (onActivityResult).
	 */
	TagBundleListAdapter.ListItem selectedListItem = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// setTitle( R.string.view__title);
		super.onCreate(savedInstanceState);
		setContentView(R.layout.tag_bundle);

		// get access to database
		osmtData = OsmtDataFactory.createOsmtData(this);

		processParams();

		initViews();
	}

	/**
	 * Get extras and set attributes.
	 */
	private void processParams() {
		// extract params
		final Bundle extras = getIntent().getExtras();
		osmtBundleId = extras.getInt("OSM_BUNDLE_ID");
		final Bundle featureBundle = extras.getBundle("OSM_FEATURE_BUNDLE");
		final long itemId = extras.getLong("ITEM_ID");

		boolean validParams = false;
		try {
			if (osmtBundleId != 0) {
				osmtBundle = new OsmtBundle(osmtData, Integer.valueOf(osmtBundleId));
				validParams = true;
			} else if (featureBundle != null) {
				resultIntent.putExtra("ITEM_ID", itemId);
				String valueName;
				boolean firstItem = true;
				for (String keyName : featureBundle.keySet()) {
					valueName = featureBundle.getString(keyName);
					if (StrUtils.isNotEmpty(valueName)) {
						OsmtFeatureRecord featureRecord = new OsmtFeatureRecord();
						if (firstItem) {
							osmtBundle = new OsmtBundle(osmtData, keyName + " = " + valueName);
							firstItem = false;
						}
						featureRecord.osmKey = keyName;
						featureRecord.osmValue = valueName;
						osmtBundle.add(featureRecord);
						validParams = true;
					}
				}
			}
			if (!validParams) {
				setResult(RESULT_CANCELED, new Intent());
				doFinish();
			}
		} catch (OsmtObjectException e) {
			// TODO Jump return
			e.printStackTrace();
		}

	}

	private void initViews() {

		// Bundle means tag-list
		lstBundleView = (ListView) findViewById(R.id.tagBundle_lstBundleView);
		lstBundleView.setAdapter(new TagBundleListAdapter(this, osmtBundle));
		lstBundleView.setOnItemClickListener(getOnKeyValueItemClickListener());
		registerForContextMenu(lstBundleView);

		// view to display the bundle's image (get image from first tag of
		// bundle)
		imgBundleImageView = (ImageView) findViewById(R.id.tagBundle_imgExampleView);
		if (osmtBundle.countOfFeatures() > 0) {
			downloadImageTask = new DownloadImageTask();
			downloadImageTask.execute(osmtBundle.getFeatureAtIndex(0));
		}

		// set Title
		TextView txtBundleNameView = (TextView) findViewById(R.id.tagBundle_txtBundleName);

		if (osmtBundle != null) {
			txtBundleNameView.setText(osmtBundle.get().displayName);
		}

	}

	/**
	 * Serves the click event that occurs when the user touches an
	 * key-value-item.
	 * 
	 * @return a OnItemClickListener event handler
	 */
	private OnItemClickListener getOnKeyValueItemClickListener() {

		return new OnItemClickListener() {

			/**
			 * On item selection start an instance of TagEditingActivity to edit
			 * the key-value-pair
			 */
			@Override
			public void onItemClick(AdapterView<?> listView, View view, int position, long id) {
				// try edit the text of selected item
				// important!!! use the classvar selectedListItem
				selectedListItem = (TagBundleListAdapter.ListItem) view.getTag();
				tryEditTagFromListItem(selectedListItem);
			}

		};
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {

		if (view == lstBundleView) {
			// get the view of the item that the event occur
			AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
			final View itemView = info.targetView;
			// get the payload, that contain the track name
			final TagBundleListAdapter.ListItem listItem = (TagBundleListAdapter.ListItem) itemView
					.getTag();
			// set context menu title
			final String selectedKeyName = listItem.keyView.getText().toString();
			final String selectedValueName = listItem.valueView.getText().toString();
			final CharSequence selectedTagName = String.format("%s=%s", selectedKeyName,
					selectedValueName);
			menu.setHeaderTitle(selectedTagName);
			// inflate context menu options
			getMenuInflater().inflate(R.menu.tag_bundle_context, menu);
		}

		super.onCreateContextMenu(menu, view, menuInfo);
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {

		AdapterView.AdapterContextMenuInfo info;
		try {
			// get the view of the item that the event occur
			info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
		} catch (ClassCastException e) {
			Log.e(Constants.TAG, "cannot detect menuInfo", e);
			return false;
		}
		// in targetView we find our view that was clicked by user
		final View itemView = info.targetView;
		// get the payload, that contain the track id

		// important!!! set the member selectedListItem, so that later
		// processing in onActivityResult is possible
		selectedListItem = (TagBundleListAdapter.ListItem) itemView.getTag();

		switch (item.getItemId()) {
		case R.id.opt_editTag:
			// try edit the text of selected item
			tryEditTagFromListItem(selectedListItem);
			break;
		case R.id.opt_addTag:
			addTag();
			break;
		case R.id.opt_deleteTag:
			deleteTag(selectedListItem.feature);
			break;
		default:
			// nothing
			break;
		}
		return super.onContextItemSelected(item);
	}

	private void deleteTag(final OsmtFeatureRecord selectedFeature) {
		final String tagPairString = selectedFeature.osmKey + "=" + selectedFeature.osmValue;
		final String msgConfirmRemovingTag = String.format(
				getString(R.string.dialog__message__confirm_removing_tag), tagPairString);
		final String msgInfoRemovedSuccessfully = String.format(
				getString(R.string.toast__message__tag_removed_successfully), tagPairString);
		final String msgInfoRemovingTagFailed = String.format(
				getString(R.string.toast__message__removing_tag_failed), tagPairString);
		final OsmtBundle bundleWithFeatureToDelete = osmtBundle;
		Dialogs.confirmationDialog(TagBundleActivity.this, msgConfirmRemovingTag,
				new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						if (bundleWithFeatureToDelete.delete(selectedFeature)) {
							refreshTagList();
							showToast(msgInfoRemovedSuccessfully);
						} else {
							showToast(msgInfoRemovingTagFailed);
						}
					}
				});
	}

	/**
	 * Starts TagEditingActivity to enter a Key Value pair.
	 */
	private void addTag() {
		final Intent tagEditingIntent = new Intent(TagBundleActivity.this,
				TagEditingActivity.class);
		// set parameters
		tagEditingIntent.putExtra("KEY", getString(R.string.tag_editing__edt_key));
		tagEditingIntent.putExtra("VALUE", getString(R.string.tag_editing__edt_value));
		// start TagEditingActivity
		startActivityForResult(tagEditingIntent, INTENT_TAG_ADD);
	}

	private boolean listItemIsEditable(TagBundleListAdapter.ListItem listItem) {
		// otherwise key and value are editable (ignore single set false)
		boolean retVal;
		if (listItem.fixKey && listItem.fixValue) {
			retVal = false;
		} else {
			retVal = true;
		}
		return retVal;
	}

	private void editTag(OsmtFeatureRecord feature) {

		final Intent tagEditingIntent = new Intent(TagBundleActivity.this,
				TagEditingActivity.class);
		// set parameters
		tagEditingIntent.putExtra("KEY", feature.osmKey);
		tagEditingIntent.putExtra("VALUE", feature.osmValue);
		// start TagEditingActivity
		startActivityForResult(tagEditingIntent, INTENT_TAG_EDIT);
	}

	/**
	 * Try to edit the tags associated with this listItem.
	 * 
	 * @param listItem the list item to edit.
	 */
	void tryEditTagFromListItem(TagBundleListAdapter.ListItem listItem) {
		if (listItemIsEditable(listItem)) {
			editTag(listItem.feature);
		} else {
			// inform the user, that this key-value-pair cannot be edited.
			final String keyName = listItem.keyView.getText().toString();
			final String valueName = listItem.valueView.getText().toString();
			final String comment = getComment(keyName, valueName);
			final String message = (StrUtils.isNotEmpty(comment) ? comment + "\n\n" : "")
					+ String.format(
							getString(R.string.tag_bundle__key_value_pair_not_editable),
							keyName + "=" + valueName);
			showToast(message);
		}
	}

	/**
	 * Requests the comment from a feature consists of the key value pair.
	 * 
	 * @param keyName The key part of the feature.
	 * @param valueName The value part of the feature.
	 * @return the founded comment.
	 */
	private String getComment(String keyName, String valueName) {
		try {
			OsmtFeature feature = new OsmtFeature(osmtData, keyName, valueName, null, null,
					null, null, null, null, null);
			final String foundedComment = feature.get().comment;
			if (StrUtils.isNotEmpty(foundedComment)) {
				return foundedComment;
			}
		} catch (OsmtObjectException e) {
			return "";
		}
		return "";
	}

	/**
	 * Process return values from TagEditor.
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		switch (requestCode) {
		case INTENT_TAG_EDIT:
			if (resultCode == RESULT_OK) {
				// if the user had confirm changes, modify the key-value-item in
				// the bundle
				Bundle resultBundle = data.getExtras();
				final String modifiedKeyName = resultBundle.getString("KEY");
				final String modifiedValueName = resultBundle.getString("VALUE");

				selectedListItem.feature.osmKey = modifiedKeyName;
				selectedListItem.feature.osmValue = modifiedValueName;

				// set modified key value to the list item (update item)
				ListItem.setListItem(selectedListItem.feature, selectedListItem);

			}
			break;
		case INTENT_TAG_ADD:
			if (resultCode == RESULT_OK) {
				Bundle resultBundle = data.getExtras();
				final String newKeyName = resultBundle.getString("KEY");
				final String newValueName = resultBundle.getString("VALUE");
				osmtBundle.add(newKeyName, newValueName);
				refreshTagList();
			}
			break;
		default: // nothing
			break;
		}
	}

	/**
	 * Is calling when the Cancel-button will be pressed.
	 * 
	 * @param view the View in which the cancel action occurred
	 */
	public void onCancelClick(View view) {
		setResult(RESULT_CANCELED, new Intent());
		doFinish();
	}

	/**
	 * Gets called when the Ok-button will be pressed.
	 * 
	 * @param view the View in which the ok click action occurred
	 */
	public void onOkClick(View view) {
		// TODO: Test : OsmtBundle.useOneMoreTime(osmtBundle);
		resultIntent.putExtra("BUNDLE_NAME", osmtBundle.get().displayName);
		resultIntent.putExtra("KEY_VALUE_BUNDLE", packResultBundle());
		// set result values
		setResult(RESULT_OK, resultIntent);
		// and return to super activity
		doFinish();
	}

	private void doFinish() {
		// TODO Auto-generated method stub
		downloadImageTask.cancel(true);
		finish();
	}

	/**
	 * Generates the key-value bundle.
	 * 
	 * @return key-value bundle
	 */
	private Bundle packResultBundle() {

		Bundle resultBundle = new Bundle();

		// iterate over the list and pack all values of items in the bundle
		int childCount = lstBundleView.getChildCount();
		TagBundleListAdapter.ListItem currentListItem;
		View currentContainerListItem;
		String currentKeyName;
		String currentValueName;

		for (int i = 0; i < childCount; i++) {
			currentContainerListItem = lstBundleView.getChildAt(i);
			currentListItem = (TagBundleListAdapter.ListItem) currentContainerListItem.getTag();

			// we return the osmName, not the displayName
			currentKeyName = currentListItem.feature.osmKey;
			currentValueName = currentListItem.feature.osmValue;
			if (currentKeyName != null && currentKeyName.length() > 0
					&& currentValueName != null && currentValueName.length() > 0)
				resultBundle.putString(currentKeyName, currentValueName);
		}
		return resultBundle;
	}

	/**
	 * Show the message in a toast.
	 * 
	 * @param message the message to appear.
	 */
	void showToast(String message) {
		Toast.makeText(TagBundleActivity.this, message, Toast.LENGTH_LONG).show();
	}

	/**
	 * Update content of tag list by renew the TagBundleListAdapter.
	 */
	void refreshTagList() {
		lstBundleView.setAdapter(new TagBundleListAdapter(this, osmtBundle));
	}

}
